(function (win) {
	var rotto = win.Ottor = win.Ottor || {};
	
	var constHelper = {
		array: [],
		string: '',
		object: {},
		regexp: {
			upperCase: /^[A-Z]+$/,
			lowerCase: /^[a-z]+$/,
			alpha: /^[a-zA-Z]+$/,
			digit: /^\d+$/,
			digitAlpha: /^[a-zA-Z0-9]+$/,
			whiteSpace: /^[ \t]+$/,
			
			trimLeft: /^ */,
			trimRight: / *$/,
			// 这是不行的
			// trimBoth: /^ *(.*) *$/,
		},
	};
	
	var typeUtil = rotto.typeUtil = rotto.typeUtil || {};
	var collectionUtil = rotto.collectionUtil = rotto.collectionUtil || {};
	
	// 类型判断
	var typeArray = ['String', 'Function', 'Array', 'Number', 'RegExp', 'Object', 'Date', 'Boolean'];
	
	/* 错误，typeArray[i]的值无法直接传递给内部函数。
	测试发现，不论执行 isString、isObject、isArray，内部函数 i 总是 8，typeArray[i] 总是 undefined。
	这样自然是不行的。只要把 for 循环的 var 改成 let 即可解决问题。
	for (var i = 0; i < typeArray.length; i++) {
		typeUtil['is' + typeArray[i]] = function (data) {
			console.log(i);
			console.log(typeArray[i]);
			return Object.prototype.toString.apply(data) == '[object ' + typeArray[i] + ']';
		};
	}
	*/

	function OttorTypeError() {
		//
	}
	
	var typeUtilExtend = {
		// 是否整数。true 是，false 否。
		isInteger: function (data) {
			if (!typeUtil.isNumber(data)) throw new TypeError('Need Number');
			return data.toString().indexOf('.') === -1;
		},
		
		// 是否 >= 0 的整数。true 是，false 否。
		isPositiveInteger: function (data) {
			if (!typeUtil.isInteger(data)) throw new TypeError('Need Integer');
			return data >= 0;
		},
		
		// 是否 <= 0 的整数。true 是，false 否。
		isNegativeInteger: function (data) {
			if (!typeUtil.isInteger(data)) throw new TypeError('Need Integer');
			return data <= 0;
		},
		// 是否 > 0 的整数。true 是，false 否。
		isAbsolutePositiveInteger: function (data) {
			if (!typeUtil.isPositiveInteger(data)) throw new TypeError('Need PositiveInteger');
			return data > 0;
		},
		
		// 是否 < 0 的整数。true 是，false 否。
		isAbsoluteNegativeInteger: function (data) {
			if (!typeUtil.isNegativeInteger(data)) throw new TypeError('Need NegativeInteger');
			return data < 0;
		},
	};
	
	var collectionUtilExtend = {
		// 扩展
		extend: win.jQuery === undefined ? function() {
			var options, name, src, copy, copyIsArray, clone,
				target = arguments[ 0 ] || {},
				i = 1,
				length = arguments.length,
				deep = false;

			// Handle a deep copy situation
			if ( typeof target === "boolean" ) {
				deep = target;

				// Skip the boolean and the target
				target = arguments[ i ] || {};
				i++;
			}

			// Handle case when target is a string or something (possible in deep copy)
			if ( typeof target !== "object" && !isFunction( target ) ) {
				target = {};
			}

			// Extend jQuery itself if only one argument is passed
			if ( i === length ) {
				target = this;
				i--;
			}

			for ( ; i < length; i++ ) {

				// Only deal with non-null/undefined values
				if ( ( options = arguments[ i ] ) != null ) {

					// Extend the base object
					for ( name in options ) {
						src = target[ name ];
						copy = options[ name ];

						// Prevent never-ending loop
						if ( target === copy ) {
							continue;
						}

						// Recurse if we're merging plain objects or arrays
						if ( deep && copy && ( jQuery.isPlainObject( copy ) ||
							( copyIsArray = Array.isArray( copy ) ) ) ) {

							if ( copyIsArray ) {
								copyIsArray = false;
								clone = src && Array.isArray( src ) ? src : [];

							} else {
								clone = src && jQuery.isPlainObject( src ) ? src : {};
							}

							// Never move original objects, clone them
							target[ name ] = jQuery.extend( deep, clone, copy );

						// Don't bring in undefined values
						} else if ( copy !== undefined ) {
							target[ name ] = copy;
						}
					}
				}
			}

			// Return the modified object
			return target;
		} : function () {
			jQuery.extend.apply(this, arguments);
		},
		
		// 来自 Ueditor，当然是成功。
		foreach: function (data, iterator, context) {
			if (data == null) return;
			if (data.length === +data.length) {
				for (var i = 0, l = data.length; i < l; i++) {
					if(iterator.call(context, data[i], i, data) === false)
						return false;
				}
			} else {
				for (var key in data) {
					if (data.hasOwnProperty(key)) {
						if(iterator.call(context, data[key], key, data) === false)
							return false;
					}
				}
			}
		},
		
		// 元素在数组中的索引
		// arr.indexOf 默认就是严格模式。
		indexOfArray: constHelper.array.indexOf ? function (haystack, needle, fromIndex) {
			if (!typeArray.isArray(haystack)) throw new TypError('Need Array');
			return constHelper.array.apply(haystack, [needle, fromIndex]);
		} : function (haystack, needle) {
			if (!typeArray.isArray(haystack)) throw new TypError('Need Array');
			if (fromIndex < 0) {
				fromIndex = haystack.length + fromIndex;
			}
			for (var i = 0; i < haystack.length; i++) {
				//if ()
				if (haystack[i] === needle) return i;
			}
			return -1;
		},
		
		// 严格模式
		inArray: collectionUtil.inArray || function (haystack, needel) {
			if (!typeUtil.isArray(haystack)) throw new TypError('Need Array');
			return 
		},
		
		// 扩展原型对象
		// extend = {a:f, b:f, ...}
		extendPrototype: function (proto, extend) {
			for (var method in extend) {
				if (extend.hasOwnProperty(method) && !proto[method]) {
					proto[method] = extend[method];
				}
			}
		},
	};
	
	collectionUtilExtend.extend(collectionUtil, collectionUtilExtend);
	
	collectionUtil.foreach(typeArray, function (v) {
		typeUtil['is' + v] = function (obj) {
			return Object.prototype.toString.apply(obj) == '[object ' + v + ']';
		}
	});
	
	var stringProtoExtend = {
		// 一个字符串中，是否只有字母且至少有一个字母。true 是，false 否。空字符串 为 false。
		// 允许只有大写字母、只有小写字母、大小写混合等情况。
		isAlpha: function () {
			return constHelper.regexp.alpha.test(this);
		},
		
		// 一个字符串中，是否只有数字。true 是，false 否。空字符串 为 false。
		isDigit: function () {
			return constHelper.regexp.digit.test(this);
		},
		
		// 一个字符串中，是否只有数字和字母。true 是，false 否。空字符串 为 false。
		// 允许只有大写字母、只有小写字母、只有数字、以及它们的任意混合等情况。
		isDigitAlpha: function () {
			return constHelper.regexp.digitAlpha.test(this);
		},
		
		// 一个字符串中，是否只有空白字符（空格、制表符）。true 是，false 否。空字符串 为 false。
		isWhiteSpace: function () {
			return constHelper.regexp.whiteSpace.test(this);
		},
		
		// 一个字符串中，是否全部大写字母。true 是，false 否。空字符串 为 false。
		isUpper: function () {
			return constHelper.regexp.upperCase.test(this);
		},
		
		// 一个字符串中，是否全部小写字母。true 是，false 否。空字符串 为 false。
		isLower: function () {
			return constHelper.regexp.lowerCase.test(this);
		},
		
		// 是否以指定字符串开始。true 是，false 否。空字符串 为 false。
		startsWith: function (data) {
			if (data === '') return false;
			return this.indexOf(data) === 0;
		},
		
		// 是否以指定字符串结尾。true 是，false 否。空字符串 为 false。
		endsWith: function (data) {
			return this.contains(data) && (data === (this.substr(this.indexOf(data))));
		},
		
		// 是否包含指定字符串。true 是，false 否。空字符串 为 false。
		contains: function (data) {
			if (data === '') return false;
			return this.indexOf(data) > -1;
		},
		
		// 移除左侧（不改变自己）
		trimLeft: function (trimStr) {
			if (trimStr && typeUtil.isString(trimStr)) {
				var reg = new RegExp('^('+ trimStr +')*');
				return this.replace(reg, '');
			} else {
				return this.replace(constHelper.regexp.trimLeft, '');
			}
		},
		
		// 移除右侧（不改变自己）
		trimRight: function (trimStr) {
			if (trimStr && typeUtil.isString(trimStr)) {
				var reg = new RegExp('('+ trimStr +')*$');
				return this.replace(reg, '');
			} else {
				return this.replace(constHelper.regexp.trimRight, '');
			}
		},
		
		// 移除两侧（不改变自己）
		trim: function (trimStr) {
			if (trimStr && typeUtil.isString(trimStr)) {
				var regLeft = new RegExp('^('+ trimStr +')*');
				var regRight = new RegExp('('+ trimStr +')*$');
				// 这是不行的
				// var reg = new RegExp('^('+ trimStr +')*(.*)('+ trimStr +')*$');
				return this.replace(regLeft, '').replace(regRight, '');
			} else {
				return this.replace(constHelper.regexp.trimLeft, '').replace(constHelper.regexp.trimRight, '');
			}
		},
		
		// 是否邮箱。true 是，false 否。
		isEmail: function () {
			return false;
		},
		
		// 是否手机号码。true 是，false 否。
		isMobile: function () {
			return false;
		},
		
		// 是否座机号码。true 是，false 否。
		isTelephone: function () {
			return false;
		},
		
		// 是否电话号码。true 是，false 否。
		isPhone: function () {
			return false;
		},
		
		// 是否身份证号码。true 是，false 否。
		isIdentity: function () {
			return false;
		},
	};
	
	collectionUtilExtend.extendPrototype(String.prototype, stringProtoExtend);
	
	var arrayProtoExtend = {
		indexOf: function (element, from, to) {
			if (this.length === 0) {
				return -1;
			}

			if (from == undefined) {
				from = 0;
			}

			if (to == undefined) {
				to = this.length - 1;
			}

			// 如果传递了，但不是整数。
			if (!typeUtil.isInteger(from)) {
				throw new TypeError('paramter 2 must be a Integer');
			}

			// 如果传递了，但不是整数。
			if (!typeUtil.isInteger(to)) {
				throw new TypeError('paramter 2 must be a Integer');
			}

			if (from < 0) {
				from = this.length + from;
			}

			if (to < 0) {
				to = this.length + to;
			}

			if (from > this.length - 1) {
				throw new Error('from out array length');
			}

			if (to > ) {}

			for (var i = 0; i < this.length; i++) {
				if (this[i] === element) {
					return i;
				}
			}

			return -1;
		},
		// 
		pushAll: function (other) {
			for (var i = 0; i < other.length; i++) {
				this.push(other[i]);
			}
		},
		contains: function (element) {
			return this.indexOf(element) > -1;
		}
	};
	
}) (this);